﻿#include "stdafx.h"
#include "FboColorPick.h"
#include "Shader.h"
#include "RenderObject.h"

FboColorPick::FboColorPick()
{
	m_colorBuffer = m_depthBuffer = 0;
}


FboColorPick::~FboColorPick()
{
	glDeleteRenderbuffers(1, &m_colorBuffer);
	glDeleteRenderbuffers(1, &m_depthBuffer);
	glDeleteFramebuffers(1, &m_fbo);
}

bool FboColorPick::Init()
{
	glGenRenderbuffers(1, &m_colorBuffer);
	glGenRenderbuffers(1, &m_depthBuffer);
	glGenFramebuffers(1, &m_fbo);
	int w = 1, h = 1;
	glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
	glBindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, w, h);
	glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorBuffer);
	//glBindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer[1]);
	//glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, w, h);
	//glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, m_colorBuffer[1]);
	glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
	glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer);
	// check FBO status
	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	if (status != GL_FRAMEBUFFER_COMPLETE)
		return false;

	// switch back to window-system-provided framebuffer
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glBindRenderbuffer(GL_RENDERBUFFER, 0);
	return true;
}

void FboColorPick::Viewport(UINT x, UINT y, UINT w, UINT h)
{
	m_viewport_x = x;
	m_viewport_y = y;
	m_viewport_w = w;
	m_viewport_h = h;
	glBindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, w, h);
	//glBindRenderbuffer(GL_RENDERBUFFER, m_colorBuffer[1]);
	//glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, w, h);
	glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
	GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
	assert(status == GL_FRAMEBUFFER_COMPLETE);
	glBindRenderbuffer(GL_RENDERBUFFER, 0);
}

void FboColorPick::Use()
{
	glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
	//static const GLenum colors[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
	//glDrawBuffers(2, colors);
	glViewport(0, 0, m_viewport_w, m_viewport_h);
	glClearColor(0.f, 0.f, 0.f, 1.f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

BoundBoxObject *FboColorPick::Pick(UINT x, UINT y)
{
	UINT buf = 0;
	Use();
	Draw();
	//glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
	//glReadBuffer(GL_COLOR_ATTACHMENT0);
	glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &buf);
	End();
	UINT id = buf & 0xffffff;
	int count = m_boundBoxObjs.size();
	if (id && (id <= count))
	{
		return m_boundBoxObjs[id - 1];
	}
	return nullptr;
}

//RenderObject *FboColorPick::Find(UINT id)
//{
//	for (auto obj : m_renderObjs)
//	{
//		if (obj->GetId() == id)
//		{
//			return obj;
//		}
//	}
//	return nullptr;
//}

void FboColorPick::End()
{
	//glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
	//glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glViewport(m_viewport_x, m_viewport_y, m_viewport_w, m_viewport_h);
	//glClearColor(0.f, 0.f, 0.f, 1.f);
	//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//glReadBuffer(GL_COLOR_ATTACHMENT0);
	//glBlitFramebuffer(0, 0, m_viewport_w, m_viewport_h, m_viewport_x, m_viewport_y, m_viewport_x + m_viewport_w, m_viewport_y + m_viewport_h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
extern glm::vec3 g_boundBoxMin;
extern glm::vec3 g_boundBoxMax;
void FboColorPick::Draw()
{
	UINT count = m_boundBoxObjs.size();
	if (!count) return;
	Shaders::GetInstance()->m_sBoundBox.UseProgram();
	UniformBufferObject &ubo = Shaders::GetInstance()->m_uboDrawInst;
	glBindVertexArray(Shaders::GetInstance()->m_vaoNoVert);
	ubo.Bind();
	auto p = &m_boundBoxObjs[0];
	for (UINT i = 0; i < count; i++)
	{
		(*p)->m_drawParam.color = f32_rgba_cast(i + 1);
		//DrawBoundBoxParam dbb((*p)->m_drawParam);
		//dbb.bdMin = glm::vec4(g_boundBoxMin, 1);
		//dbb.bdMax = glm::vec4(g_boundBoxMax, 1);
		//ubo.SetBufferData(sizeof(DrawBoundBoxParam) * i, sizeof(DrawBoundBoxParam), &dbb, false);
		ubo.SetBufferData(sizeof(DrawBoundBoxParam) * i, sizeof(DrawBoundBoxParam), &(*p)->m_drawParam, false);
		p++;
	}
	ubo.UnBind();
	glDrawArraysInstanced(GL_POINTS, 0, 1, count);
	glBindVertexArray(0);
	Shaders::GetInstance()->m_sBoundBox.UseProgram0();
}

void FboColorPick::Add(BoundBoxObject *box)
{
	int size = m_boundBoxObjs.size();
	assert(size < 500);
	m_boundBoxObjs.push_back(box);
}

void FboColorPick::Clear()
{
	m_boundBoxObjs.clear();
}